<template>
  <section ref="treeCardRef" style="height: 100%">
    <a-card :bordered="false" :bodyStyle="{ padding: '16px', height: '100%', overflow: 'auto' }">
      <section ref="treeActionRef">
        <div class="j-table-operator" style="width: 100%">
          <a-tooltip title="新增">
            <a-button type="primary" size="small" preIcon="ant-design:plus-outlined" @click="onAddDepart" />
          </a-tooltip>
          <a-tooltip title="添加下级">
            <a-button type="text" size="small" preIcon="ant-design:plus-outlined" @click="onAddChildDepart()" />
          </a-tooltip>
          <a-tooltip title="导入">
            <a-upload name="file" :showUploadList="false" :customRequest="onImportXls">
              <a-button type="text" preIcon="ant-design:import-outlined" />
            </a-upload>
          </a-tooltip>
          <a-tooltip title="导出">
            <a-button type="text" preIcon="ant-design:export-outlined" @click="onExportXls" />
          </a-tooltip>
          <template v-if="checkedKeys.length > 0">
            <a-dropdown>
              <template #overlay>
                <a-menu>
                  <a-menu-item key="1" @click="onDeleteBatch">
                    <icon icon="ant-design:delete-outlined" />
                    <span>删除</span>
                  </a-menu-item>
                </a-menu>
              </template>
              <a-tooltip title="批量操作">
                <a-button type="text" preIcon="akar-icons:chevron-down" />
              </a-tooltip>
            </a-dropdown>
          </template>
        </div>
        <a-alert type="info" show-icon class="alert" style="margin-bottom: 8px">
          <template #message>
            <template v-if="checkedKeys.length > 0">
              <span>已选中 {{ checkedKeys.length }} 条记录</span>
              <a-divider type="vertical" />
              <a @click="checkedKeys = []">清空</a>
            </template>
            <span v-else>未选中任何数据</span>
          </template>
        </a-alert>
        <a-input-search placeholder="按部门名称搜索…" style="margin-bottom: 10px" @search="onSearch" />
      </section>

      <a-spin :spinning="loading">
        <section ref="treeContext">
          <!--组织机构树-->
          <template v-if="treeData.length > 0">
            <a-tree
              v-if="!treeReloading"
              checkable
              :clickRowToExpand="false"
              :style="{ height: `${treeContextHeight - treeActionHeight - 32}px`, overflow: 'auto' }"
              :treeData
              :selectedKeys
              :checkStrictly
              :load-data="loadChildrenTreeData"
              :checkedKeys
              v-model:expandedKeys="expandedKeys"
              @check="onCheck"
              @select="onSelect"
              class="left-tree"
            >
              <template #title="{ key: treeKey, title, dataRef }">
                <a-dropdown :trigger="['contextmenu']">
                  <Popconfirm
                    :open="visibleTreeKey === treeKey"
                    title="确定要删除吗？"
                    ok-text="确定"
                    cancel-text="取消"
                    placement="rightTop"
                    @confirm="onDelete(dataRef)"
                    @open-change="onVisibleChange"
                  >
                    <span>{{ title }}</span>
                  </Popconfirm>
                  <template #overlay>
                    <a-menu>
                      <a-menu-item key="1" @click="onAddChildDepart(dataRef)">添加子级</a-menu-item>
                      <a-menu-item key="2" @click="visibleTreeKey = treeKey">
                        <span style="color: red">删除</span>
                      </a-menu-item>
                    </a-menu>
                  </template>
                </a-dropdown>
              </template>
            </a-tree>
          </template>
          <a-empty v-else description="暂无数据" />
        </section>
      </a-spin>
      <form-modal :treeData @register="registerModal" @success="loadRootTreeData" />
    </a-card>
  </section>
</template>

<script lang="ts" setup>
  import { computed, nextTick, ref, unref, useTemplateRef } from 'vue';
  import { useModal } from '/@/components/Modal';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { useMethods } from '/@/hooks/system/useMethods';
  import { Api, deleteBatchDepart, queryDepartTreeSync } from '../api';
  import { searchByKeywords } from '/@/views/system/departUser/depart.user.api';
  import FormModal from './formModal.vue';
  import { Popconfirm } from 'ant-design-vue';

  const emit = defineEmits(['select', 'rootTreeData']);
  const { createMessage } = useMessage();
  const { handleImportXls, handleExportXls } = useMethods();
  const treeCardRef = useTemplateRef('treeCardRef');
  const treeActionRef = useTemplateRef('treeActionRef');

  const treeContextHeight = computed(() => {
    return treeCardRef?.value?.clientHeight ?? 100;
  });
  const treeActionHeight = computed(() => {
    return treeActionRef?.value?.clientHeight ?? 0;
  });

  const loading = ref<boolean>(false);
  // 部门树列表数据
  const treeData = ref<any[]>([]);
  // 当前选中的项
  const checkedKeys = ref<any[]>([]);
  // 当前展开的项
  const expandedKeys = ref<any[]>([]);
  // 当前选中的项
  const selectedKeys = ref<any[]>([]);
  // 树组件重新加载
  const treeReloading = ref<boolean>(false);
  // 树父子是否关联
  const checkStrictly = ref<boolean>(true);
  // 当前选中的部门
  const currentDepart = ref<any>(null);
  // 控制确认删除提示框是否显示
  const visibleTreeKey = ref<any>(null);
  // 搜索关键字
  const searchKeyword = ref('');

  // 注册 modal
  const [registerModal, { openModal }] = useModal();

  // 加载顶级部门信息
  async function loadRootTreeData() {
    try {
      loading.value = true;
      treeData.value = [];
      const result = await queryDepartTreeSync();
      if (Array.isArray(result)) {
        treeData.value = result;
      }
      if (expandedKeys.value.length === 0) {
        autoExpandParentNode();
      } else {
        if (selectedKeys.value.length === 0) {
          const item = treeData.value[0];
          if (item) {
            // 默认选中第一个
            setSelectedKey(item.id, item);
          }
        } else {
          emit('select', currentDepart.value);
        }
      }
      emit('rootTreeData', treeData.value);
    } finally {
      loading.value = false;
    }
  }

  loadRootTreeData();

  // 加载子级部门信息
  async function loadChildrenTreeData(treeNode: any) {
    try {
      const result = await queryDepartTreeSync({
        pid: treeNode.dataRef.id,
      });
      if (result.length === 0) {
        treeNode.dataRef.isLeaf = true;
      } else {
        treeNode.dataRef.children = result;
        if (expandedKeys.value.length > 0) {
          // 判断获取的子级是否有当前展开的项
          const subKeys: any[] = [];
          for (let key of expandedKeys.value) {
            if (result.findIndex((item: any) => item.id === key) !== -1) {
              subKeys.push(key);
            }
          }
          if (subKeys.length > 0) {
            expandedKeys.value = [...expandedKeys.value];
          }
        }
      }
      treeData.value = [...treeData.value];
      emit('rootTreeData', treeData.value);
    } catch (e) {
      console.error(e);
    }
    return Promise.resolve();
  }

  // 自动展开父节点，只展开一级
  function autoExpandParentNode() {
    const [item] = treeData.value;
    if (item) {
      if (!item.isLeaf) {
        expandedKeys.value = [item.key];
      }
      // 默认选中第一个
      setSelectedKey(item.id, item);
      reloadTree();
    } else {
      emit('select', null);
    }
  }

  // 重新加载树组件，防止无法默认展开数据
  async function reloadTree() {
    await nextTick();
    treeReloading.value = true;
    await nextTick();
    treeReloading.value = false;
  }

  /**
   * 设置当前选中的行
   */
  function setSelectedKey(key: string, data?: object) {
    selectedKeys.value = [key];
    if (data) {
      currentDepart.value = data;
      emit('select', data);
    }
  }

  // 添加一级部门
  function onAddDepart() {
    openModal(true, { isUpdate: false, isChild: false });
  }

  // 添加子级部门
  function onAddChildDepart(data = currentDepart.value) {
    if (!data) {
      createMessage.warning('请先选择一个部门');
      return;
    }
    const record = { parentId: data.id };
    openModal(true, { isUpdate: false, isChild: true, record });
  }

  // 搜索事件
  async function onSearch(value: string) {
    if (value) {
      try {
        loading.value = true;
        treeData.value = [];
        let result = await searchByKeywords({ keyWord: value });
        if (Array.isArray(result)) {
          treeData.value = result;
        }
        autoExpandParentNode();
      } finally {
        loading.value = false;
      }
    } else {
      loadRootTreeData();
    }
    searchKeyword.value = value;
  }

  // 树复选框选择事件
  function onCheck(e: any) {
    checkedKeys.value = Array.isArray(e) ? e : e.checked;
  }

  // 树选择事件
  function onSelect(selKeys: any, event: any) {
    if (selKeys.length > 0 && selectedKeys.value[0] !== selKeys[0]) {
      setSelectedKey(selKeys[0], event.selectedNodes[0]);
    } else {
      // 这样可以防止用户取消选择
      setSelectedKey(selectedKeys.value[0]);
    }
  }

  /**
   * 根据 ids 删除部门
   * @param idListRef array
   * @param confirm 是否显示确认提示框
   */
  async function doDeleteDepart(idListRef, confirm = true) {
    const idList = unref(idListRef);
    if (idList.length > 0) {
      try {
        loading.value = true;
        await deleteBatchDepart({ ids: idList.join(',') }, confirm);
        await loadRootTreeData();
      } finally {
        loading.value = false;
      }
    }
  }

  // 删除单个部门
  async function onDelete(data: any) {
    if (data) {
      onVisibleChange(false);
      doDeleteDepart([data.id], false);
    }
  }

  // 批量删除部门
  async function onDeleteBatch() {
    await doDeleteDepart(checkedKeys);
    checkedKeys.value = [];
  }

  function onVisibleChange(visible: boolean) {
    if (!visible) {
      visibleTreeKey.value = null;
    }
  }

  function onImportXls(d) {
    handleImportXls(d, Api.importExcelUrl, () => loadRootTreeData());
  }

  function onExportXls() {
    const params = {};
    if (checkedKeys.value?.length > 0) {
      params['selections'] = checkedKeys.value.join(',');
    }
    handleExportXls('部门信息', Api.exportXlsUrl, params);
  }

  defineExpose({ loadRootTreeData });
</script>
<style lang="less">
  .left-tree .ant-tree-node-content-wrapper span {
    white-space: nowrap;
    text-overflow: ellipsis;
    word-break: break-all;
  }
</style>
